﻿//  Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
//  Licensed MIT: http://www.opensource.org/licenses/mit-license.php

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Linq;

namespace DNA.Mvc.Notification
{
    /// <summary>
    /// Define the helper class that using NotifcationService.
    /// </summary>
    public class NotificationService : INotificationService
    {
        public NotificationService(ISubscriptionRepository repository)
        {
            this.Subscriptions = repository;

            if (DependencyResolver.Current != null)
                Senders = DependencyResolver.Current.GetServices<ISubscriptionSender>().ToList();
            else
                Senders = new List<ISubscriptionSender>();
        }

        /// <summary>
        /// Gets the Subscriptoin Repository object.
        /// </summary>
        public virtual ISubscriptionRepository Subscriptions { get; private set; }

        /// <summary>
        /// Gets / Sets the available Subscription Sender instances.
        /// </summary>
        public virtual List<ISubscriptionSender> Senders { get; private set; }

        /// <summary>
        /// Gets whether is the user  in subscription list.
        /// </summary>
        /// <param name="token">The token that identity the subscription list.</param>
        /// <param name="userName">The registered user name.</param>
        /// <returns>Return true when user is in subscription list.</returns>
        public virtual bool IsSubscribed(string token, string userName)
        {
            return Subscriptions.IsSubscribed(token, userName);
        }

        /// <summary>
        /// Send message to subscribes
        /// </summary>
        /// <param name="token">Specified the token identify who subscribes this message</param>
        /// <param name="message">Specified the message instance</param>
        public virtual void Send(string token, IMessage message)
        {
            if (message == null)
                throw new ArgumentNullException("message");
            if (string.IsNullOrEmpty(token))
                throw new ArgumentNullException("token");

            if (Subscriptions != null)
            {
                var subscribers = Subscriptions.GetSubscribers(token);
                if ((subscribers != null) && (subscribers.Length > 0))
                {
                    //Senders.AsParallel()
                    //    .ForAll(sender =>
                    //    {
                    //        AnsyncSendAction.BeginInvoke(sender, subscribers, message, null, null);
                    //    });
                    var senders = Senders;
                    
                    foreach (var sender in senders)
                    {
                        try
                        {
                            AnsyncSendAction.BeginInvoke(sender, subscribers, message, null, null);
                        }
                        catch { continue; }
                    }
                }
            }
        }

        /// <summary>
        /// Send a simple mesage.
        /// </summary>
        /// <param name="token">The token that identity the subscription list.</param>
        /// <param name="title">Specified the message title.</param>
        /// <param name="content">Specified the message content.</param>
        /// <param name="contentType">Identity the message content type.</param>
        /// <param name="encoding">Specified the content encoding.</param>
        public virtual void Send(string token, string title, string content, string contentType = "text/html", string encoding = "utf-8", string type = "")
        {
            var msg = new SimpleMessage()
            {
                Title = title,
                Content = content,
                ContentType = contentType,
                Encoding = encoding,
                TypeName = type
            };
            Send(token, msg);
        }

        private static readonly Action<ISubscriptionSender, string[], IMessage> AnsyncSendAction = new Action<ISubscriptionSender, string[], IMessage>((sender, subscribers, message) =>
        {
            if ((sender != null) && (subscribers != null) && (message != null))
                sender.Send(subscribers, message);
        });

        /// <summary>
        /// Remove the user from subscription list.
        /// </summary>
        /// <param name="token">Specified the token identify who subscribes this message</param>
        /// <param name="userName">Specified the unsubscribe user name</param>
        public virtual void Unsubscribe(string token, string userName)
        {
            if (string.IsNullOrEmpty(token))
                throw new ArgumentNullException("token");
            if (string.IsNullOrEmpty(userName))
                throw new ArgumentNullException("userName");
            if (Subscriptions != null)
            {
                Subscriptions.Unsubscribe(token, userName);
                Subscriptions.Submit();
            }
        }

        /// <summary>
        /// Subscripts a new message
        /// </summary>
        /// <param name="token">Specified the token identify who subscribes this message</param>
        /// <param name="userName">Specified the subscribe user name</param>
        /// <returns></returns>
        public virtual bool Subscribe(string token, string userName)
        {
            if (string.IsNullOrEmpty(token))
                throw new ArgumentNullException("token");

            if (string.IsNullOrEmpty(userName))
                throw new ArgumentNullException("userName");

            if (Subscriptions != null)
            {
                var result = Subscriptions.Subscribe(token, userName);
                Subscriptions.Submit();
                return result;
            }

            return false;
        }

        /// <summary>
        /// Gets a subscription list by specified token.
        /// </summary>
        /// <param name="token">Specified the subscription list token.</param>
        /// <returns>Returns user name arrary.</returns>
        public string[] GetSubscribers(string token)
        {
            if (string.IsNullOrEmpty(token))
                throw new ArgumentNullException("token");

            return Subscriptions.GetSubscribers(token);
        }
    }
}
